#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "reload_configuration.h"
#include "http_server.h"
#include "socket.h"
#include "configuration.h"
#include "log.h"

#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif /* O_LARGEFILE */

extern configuration_t conf;
extern configuration_t mime_types;

extern const char *config_file;
extern const char *mime_types_file;

void reload_configuration (void)
{
	configuration_t tmp_conf;
	configuration_t tmp_mime_types;
	http_server_t tmp_http_server;

	/* Initialize configuration. */
	configuration_init (&tmp_conf, 1);
	configuration_init (&tmp_mime_types, 1);

	if (configuration_load (&tmp_conf, config_file) < 0) {
		configuration_free (&tmp_conf);

		if (http_server.log_fd != -1) {
			log_error ("Couldn't load config file %s when handling SIGHUP.", config_file);
		}

		return;
	}

	if (configuration_load (&tmp_mime_types, mime_types_file) < 0) {
		configuration_free (&tmp_mime_types);
		configuration_free (&tmp_conf);

		if (http_server.log_fd != -1) {
			log_error ("Couldn't load MIME types file %s when handling SIGHUP.", mime_types_file);
		}

		return;
	}

	if (http_server_load_configuration (&tmp_http_server, &tmp_conf) < 0) {
		http_server_delete (&tmp_http_server);
		configuration_free (&tmp_mime_types);
		configuration_free (&tmp_conf);

		if (http_server.log_fd != -1) {
			log_error ("Couldn't load HTTP server configuration when handling SIGHUP.");
		}

		return;
	}

	/* If we have log file... */
	if (tmp_http_server.logfile) {
		/* If it has changed... */
		if ((!http_server.logfile) || (strcmp (http_server.logfile, tmp_http_server.logfile) != 0)) {
			/* Open log file. */
			tmp_http_server.log_fd = open (tmp_http_server.logfile, O_CREAT | O_WRONLY | O_APPEND | O_LARGEFILE, 0644);
			if (tmp_http_server.log_fd < 0) {
				http_server_delete (&tmp_http_server);
				configuration_free (&tmp_mime_types);
				configuration_free (&tmp_conf);

				if (http_server.log_fd != -1) {
					log_error ("Couldn't open log file (%s) when handling SIGHUP.", tmp_http_server.logfile);
				}

				return;
			}
		}
	}

	/* If we have proxy log file... */
	if (tmp_http_server.proxy_logfile) {
		/* If it has changed... */
		if ((!http_server.proxy_logfile) || (strcmp (http_server.proxy_logfile, tmp_http_server.proxy_logfile) != 0)) {
			/* Open proxy log file. */
			tmp_http_server.proxy_log_fd = open (tmp_http_server.proxy_logfile, O_CREAT | O_WRONLY | O_APPEND | O_LARGEFILE, 0644);
			if (tmp_http_server.proxy_log_fd < 0) {
				http_server_delete (&tmp_http_server);
				configuration_free (&tmp_mime_types);
				configuration_free (&tmp_conf);

				if (http_server.log_fd != -1) {
					log_error ("Couldn't open proxy log file (%s) when handling SIGHUP.", tmp_http_server.proxy_logfile);
				}

				return;
			}
		}
	}

	/* If the port has changed... */
	if (http_server.port != tmp_http_server.port) {
		if ((tmp_http_server.listener = create_listener_socket (tmp_http_server.port)) < 0) {
			http_server_delete (&tmp_http_server);
			configuration_free (&tmp_mime_types);
			configuration_free (&tmp_conf);

			if (http_server.log_fd != -1) {
				log_error ("Couldn't create listener socket on port: %u when handling SIGHUP.", tmp_http_server.port);
			}

			return;
		}

		/* Add listener to the event manager descriptor. */
		if (http_server.fn_add_fd (tmp_http_server.listener, EVENT_IN) < 0) {
			http_server_delete (&tmp_http_server);
			configuration_free (&tmp_mime_types);
			configuration_free (&tmp_conf);

			if (http_server.log_fd != -1) {
				log_error ("Couldn't add listener to the event manager descriptor when handling SIGHUP.");
			}

			return;
		}
	}

	http_server_copy (&http_server, &tmp_http_server);

	configuration_free (&mime_types);
	configuration_free (&conf);

	memcpy (&mime_types, &tmp_mime_types, sizeof (configuration_t));
	memcpy (&conf, &tmp_conf, sizeof (configuration_t));

	if (http_server.log_fd != -1) {
		log_error ("[SIGHUP] Configuration has been successfully reloaded.");
	}
}
